<template>
  <div :class="{'z-form-template--inline': inline}"
       v-if="page && page.inited" class="form-template">
    <form-loader :listener="listener" @fire="private_handle_onFire"
                 :name="res.comName"
                 :inject-data="{inline}"
                 @loaded="private_handle_onFormLoaded"></form-loader>
    <slot name="after" v-bind="exportScope"></slot>
<!--    <slot name="array_beforebegin" v-bind="exportScope"></slot>-->
  </div>
</template>

<script>
import * as res from './static'

export default {
  name: 'ZFormTemplate',
  props: ['tableName', 'activeNo', 'def', 'slots', 'inline', 'labelInline', 'customDef', 'readonly', 'disabled'],
  provide() {
    let self = this
    // console.log(self.$props)
    return {
      ZFormTemplateIns: {
        // inline: this.inline,
        getProps() {
          return self.$props
        },
        register(key, value) {
          self.map.set(key, value)
        },
        unRegister(key) {
          self.map.delete(key)
        },
        getSlots() {
          return self.$scopedSlots
        }
      }
    }
  },
  watch: {
    labelInline(newVal) {
      this.map.forEach(item => {
        item('labelInline', newVal, {labelInline: newVal})
      })
    }
  },
  data() {
    let self = this
    return {
      map: new Map(),
      page: {
        formConfig: {},
        inited: false
      },
      res: {},
      exportScope: {
        curFormCtx: null
      },
      listener: {
        // ['form-submit']: function (args) {
        //   console.log(self, args)
        //   // self.onSubmitForm(args)
        // }
      },
      url: new URL(location.href),
      // storeName: STORE_NAME,
    }
  },
  async beforeMount() {
    // this.initPage()
    // console.log('beforeMount', this.def, this.slots)
    // console.log('beforeMount', this.tableName, this.activeNo)
    // await this.initPageFromServer(this.tableName, this.activeNo)
    // await this.initPageFromStatic()
    // console.log(this.def)
    await this.initPageFromObj(this.def, this.slots, this.customDef)
  },
  beforeDestroy() {
    // console.log(this.res)
    if (this?.res?.id) {
      let c = document.body.querySelector('#' + this?.res?.id)
      if (c) {
        c.remove()
      }
    }
  },
  methods: {
    private_handle_onFormLoaded({context}) {
      this.curFormCtx = context
      // console.log(context.getCurForm())
      this.exportScope.curFormCtx = context
      this.$nextTick(() => {
        this.$emit('ready', {
          ctx: this,
          form: context.getCurForm(),
          curFormCtx: context
        })
        // console.log('emit ready')
      })
    },
    private_handle_onFire(args) {
      // console.log(args)
      // let form = this.getCurForm()
      // console.log(form)
      let ctx = {}
      // ctx = form ?? {}
      // if (args[1] && args[1].scope) {
      //   // ctx.scope = args[1].scope
      //   ctx = form ?? {}
      //   // ctx.getData = function () {
      //   //   let scope = args[1].scope
      //   //   // console.log(form)
      //   //   if (scope)  {
      //   //     if (scope.parts[scope.partName]) {
      //   //       return scope.parts[scope.partName]?.model
      //   //     }
      //   //   }
      //   //   return null
      //   // }
      // }
      args.push(ctx)


      if (args[0].startsWith('com:')) {
        // console.log(args)
        if (args[1] && args[1].scope) {
          let scope = args[1].scope
          let fields = scope.curFormCon.getCmFields()

          function getWidgetContext(name) {
            let subSelect1 = fields.get(name)
            if (subSelect1) {
              let widgetContext = subSelect1.getWidgetContext()
              if (widgetContext) {
                return widgetContext
              }
            }
          }

          // console.log(scope)

          args.push({
            getWidgetContext,
            fields,
            self_path: scope.self_path
          })
          this.$emit('com-fire', args)
        }

      }

      this.$emit('fire', args);

      if (args[0] === 'updateValue') {
        // console.log(args)
        let def = args[1].config.parts[0]
        this.$emit('model-change', args[1], def);
      }
    },
    getCurForm() {
      // console.log('call formtemplate getCurForm', this.$refs, this.curFormCtx)
      if (this.curFormCtx) {
        return this.curFormCtx.getCurForm()
      }
    },
    private_getMetas(tableName, activeNo) {
      // let url = this.url;
      // let activeNo = url
      //   .searchParams.get('activeNo');
      // let tableName = url
      //   .searchParams.get('tableName')

      let obj = {tableName: tableName, activeNo: activeNo}

      return {
        ...obj
      }
    },
    /**
     * 渲染
     * @param vueFileStr
     * @param metas
     * @returns {Promise<void>}
     */
    async private_parse(vueFileStr = '', metas = {}) {
      try {
        this.res = await globalThis.ZForm.parseVueComponent({
          template: vueFileStr, metas
        });
        return;
      } catch (e) {
        console.log('parse err', vueFileStr, e)
      }
    },
    private_resolveDef(def) {
      let globalConfig = ZY.lodash.get(def, 'globalConfig', {})
      let defMessage = globalConfig?.message ?? {}
      let defMessageEnties = Object.entries(defMessage)

      // console.log(def.properties)
      Object.entries(def.properties).forEach(([propKey, propDef]) => {
        if (propDef && Array.isArray(propDef.rules)) {
          propDef.rules = propDef.rules.map(rule => {

            defMessageEnties.forEach(([key, value]) => {
              if (rule[key] && !rule['message']) {
                if (value) {
                  // rule.message = value
                  if (typeof value === 'function') {
                    rule.message = value(propKey, propDef)
                  } else {
                    rule.message = value
                  }
                }
              }
            })
            return rule
          })
        }
      })
    },

    /**
     *
     * @returns {Promise<void>}
     */
    async initPageFromObj(def, slots, customDef) {
      let metas = this.private_getMetas(this.tableName, this.activeNo)

      this.private_resolveDef(def)

      // console.log(def)

      let vueFileStr = res.getObj(def, slots, {
        inline: this.inline
        ,customDef
      })


      // console.log(vueFileStr)
      await this.private_parse(vueFileStr, metas)
      this.page.inited = true
    },
    /**
     *
     * @returns {Promise<void>}
     */
    async initPageFromStatic(isStatic) {
      let metas = this.private_getMetas(this.tableName, this.activeNo)

      let vueFileStr = ZY.getHereDoc(res.getExampleVue())

      // console.log(vueFileStr)
      await this.private_parse(vueFileStr, metas)
      this.page.inited = true
    },
    /**
     * 从服务器拉取代码
     * @returns {Promise<void>}
     */
    async initPageFromServer(tableName, activeNo) {
      let metas = this.private_getMetas(tableName, activeNo)
      // const store_vars = await ZY_EXT.store.getItem(STORE_NAME);

      // this.page.formConfig = store_vars?.value ?? []
      // let html = document.getElementById('idtpl').innerHTML
      // console.log(html)
      if (!metas.activeNo) {
        console.log('no activeNo', err)
        return;
      }


      let [err, vueFileStr] = await ZY.awaitTo(reqVueFile({
        activeNo: metas.activeNo
      }));
      if (err) {
        console.log('get file failed', err)
        return;
      }
      ZCONSOLE.log('vueFileStr', vueFileStr)

      await this.private_parse(vueFileStr, metas)

      // console.log(this.page)
      this.page.inited = true
    },
    // async onSubmitForm({scope}) {
    //   let {ctx, partName} = scope;
    //   let [isValid, errors] = await ctx.submit(partName)
    //   if (isValid) {
    //     let model = await ctx.getRawData(partName);
    //     let metas = ctx.getMetas();
    //     console.log(model, metas)
    //     axios.post('/zy-boot/json/addJson', {
    //       tableName: metas.tableName,
    //       activeNo: metas.activeNo,
    //       model: model
    //     })
    //   }
    // },
  }
}
</script>

